From 396acf3bbbe00a192cb0ea0a9ccf91b1d8d2850b Mon Sep 17 00:00:00 2001
From: Fuwn <50817549+Fuwn@users.noreply.github.com>
Date: Sat, 24 Jan 2026 13:09:50 +0000
Subject: Initial commit

Created from https://vercel.com/new
---
 .../websites/[websiteId]/(reports)/utm/UTM.tsx     | 71 ++++++++++++++++++++++
 1 file changed, 71 insertions(+)
 create mode 100644 src/app/(main)/websites/[websiteId]/(reports)/utm/UTM.tsx

(limited to 'src/app/(main)/websites/[websiteId]/(reports)/utm/UTM.tsx')

diff --git a/src/app/(main)/websites/[websiteId]/(reports)/utm/UTM.tsx b/src/app/(main)/websites/[websiteId]/(reports)/utm/UTM.tsx
new file mode 100644
index 0000000..1399174
--- /dev/null
+++ b/src/app/(main)/websites/[websiteId]/(reports)/utm/UTM.tsx
@@ -0,0 +1,71 @@
+import { Column, Grid, Heading, Text } from '@umami/react-zen';
+import { PieChart } from '@/components/charts/PieChart';
+import { LoadingPanel } from '@/components/common/LoadingPanel';
+import { Panel } from '@/components/common/Panel';
+import { useMessages, useResultQuery } from '@/components/hooks';
+import { ListTable } from '@/components/metrics/ListTable';
+import { CHART_COLORS, UTM_PARAMS } from '@/lib/constants';
+
+export interface UTMProps {
+  websiteId: string;
+  startDate: Date;
+  endDate: Date;
+}
+
+export function UTM({ websiteId, startDate, endDate }: UTMProps) {
+  const { formatMessage, labels } = useMessages();
+  const { data, error, isLoading } = useResultQuery<any>('utm', {
+    websiteId,
+    startDate,
+    endDate,
+  });
+
+  return (
+    <LoadingPanel data={data} isLoading={isLoading} error={error} minHeight="300px">
+      {data && (
+        <Column gap>
+          {UTM_PARAMS.map(param => {
+            const items = data?.[param];
+
+            const chartData = {
+              labels: items.map(({ utm }) => utm),
+              datasets: [
+                {
+                  data: items.map(({ views }) => views),
+                  backgroundColor: CHART_COLORS,
+                  borderWidth: 0,
+                },
+              ],
+            };
+            const total = items.reduce((sum, { views }) => {
+              return +sum + +views;
+            }, 0);
+
+            return (
+              <Panel key={param}>
+                <Grid columns={{ xs: '1fr', md: '1fr 1fr' }} gap="6">
+                  <Column>
+                    <Heading>
+                      <Text transform="capitalize">{param.replace(/^utm_/, '')}</Text>
+                    </Heading>
+                    <ListTable
+                      metric={formatMessage(labels.views)}
+                      data={items.map(({ utm, views }) => ({
+                        label: utm,
+                        count: views,
+                        percent: (views / total) * 100,
+                      }))}
+                    />
+                  </Column>
+                  <Column>
+                    <PieChart type="doughnut" chartData={chartData} />
+                  </Column>
+                </Grid>
+              </Panel>
+            );
+          })}
+        </Column>
+      )}
+    </LoadingPanel>
+  );
+}
-- 
cgit v1.2.3

